package main

import (
	"io"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"

	// For init func in bootstrap package.
	"gitee.com/hp-huiw/family-expense-api/internal/bootstrap"
	_ "gitee.com/hp-huiw/family-expense-api/internal/bootstrap"
	"gitee.com/hp-huiw/family-expense-api/internal/middleware"

	"gitee.com/hp-huiw/family-expense-api/internal/db"
	"github.com/gin-gonic/gin"
	"gopkg.in/natefinch/lumberjack.v2"

	"gitee.com/hp-huiw/family-expense-api/internal/router"
	"gitee.com/hp-huiw/my-go-core/config"
)

// Uses gin in main & handler functions only. Because handler is tightly coupled with web framework, here is Gin.
// If we have to switch the framework the main function and handler should be the only place we have to refactor.
// For example, if we use gin.H everywhere that means we have more work to do during such refactoring.
func main() {
	setupLogger()

	// Gets the database connection.
	activeDB := db.GetDB()
	defer activeDB.Close()

	bootstrap.InitData(activeDB)

	// Initializes default data.
	// bootstrap.InitData(db)

	// Default returns an Engine instance with the Logger and Recovery middleware already attached.
	r := gin.Default()

	setupStaticResourceHandler(r)

	// Don't trust all proxies.
	// https://pkg.go.dev/github.com/gin-gonic/gin#section-readme
	r.SetTrustedProxies(nil)

	// Applies the global error handler middleware.
	r.Use(middleware.GlobalErrorHandlerMiddleware())

	if config.SysEnvMode.IsProdMode() {
		// Apply a default timeout to all routes
		r.Use(middleware.TimeoutMiddleware(time.Duration(config.ConfigLoader.GetAppConfig().Server.DefaultRequestTimeoutSeconds) * time.Second))
	}

	// Applies the database middleware
	r.Use(middleware.DataBaseMiddleware(activeDB))

	// Uses middleware to check on access permission.
	r.Use(middleware.AuthMiddleware)

	// Generates all handler routes.
	router.GenerateRoutes(r, activeDB)

	// If you have need more configurations go for http.Server.
	// srv := &http.Server{
	// 	Addr:    ":" + pkg.ConfigService.GetAppConfig().Server.Port,
	// 	Handler: router,
	// }

	// go func() {
	// 	// Services connections
	// 	if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
	// 		log.Fatalf("listen: %s\n", err)
	// 	}
	// }()

	// listens and serves on 0.0.0.0:8080 (for windows "localhost:8080")
	go func() {
		if err := r.Run(":" + config.ConfigLoader.GetAppConfig().Server.Port); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	// Wait for interrupt signal to gracefully shutdown the server with
	// a timeout of 5 seconds.
	quit := make(chan os.Signal, 1)

	// kill (no param) default send syscanll.SIGTERM
	// kill -2 is syscall.SIGINT
	// kill -9 is syscall. SIGKILL but can"t be catch, so don't need add it
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit

	log.Println("Shutdown Server ...")
}

func setupStaticResourceHandler(r *gin.Engine) {
	config := config.ConfigLoader.GetAppConfig()
	r.Static(config.Server.RouteRootGroupName+config.Resource.StaticResourcesUrl, config.Resource.Upload.RootFilePath)
}

// Sets system level logger.
func setupLogger() {
	logDir := "log"
	os.MkdirAll(logDir, 0755)

	logFile := &lumberjack.Logger{
		Filename:   filepath.Join(logDir, "output.log"),
		MaxSize:    10,   // megabytes before rotation
		MaxBackups: 7,    // number of old files to keep
		MaxAge:     7,    // days
		Compress:   true, // compress old logs
	}

	gin.DefaultWriter = io.MultiWriter(logFile, os.Stdout)
	log.SetOutput(gin.DefaultWriter)
}

//func setupCustomRecovery(router *gin.Engine) {
//	// Recovery middleware recovers from any panics and writes a 500 if there was one.
//	router.Use(gin.CustomRecovery(func(c *gin.Context, recovered any) {
//		if err, ok := recovered.(string); ok {
//			c.ToString(http.StatusInternalServerError, fmt.Sprintf("error: %v", err))
//		}
//
//		c.AbortWithStatus(http.StatusInternalServerError)
//	}))
//}
